package com.pay.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.google.common.eventbus.EventBus;
import com.pay.common.constants.Constants;
import com.pay.dao.PayOrderMapper;
import com.pay.domain.po.PayOrder;
import com.pay.domain.req.ShopCartReq;
import com.pay.domain.res.PayOrderRes;
import com.pay.domain.vo.ProductVO;
import com.pay.service.IOrderService;
import com.pay.service.rpc.ProductRPC;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author ZhouYihe 1552951165@qq.com
 * @create 2024/10/26 21:44
 * @description 订单服务
 */
@Slf4j
@Service
public class OrderServiceImpl implements IOrderService {
    
    @Value("${alipay.notify_url}")
    private String notifyUrl;
    @Value("${alipay.return_url}")
    private String returnUrl;
    
    @Resource
    private PayOrderMapper payOrderMapper;
    
    @Resource
    private ProductRPC productRPC;
    
    @Resource
    private AlipayClient alipayClient;
    
    @Resource
    private EventBus eventBus;
    
    /**
     * 创建订单
     *
     * @param shopCartReq
     * @return
     * @throws Exception
     */
    @Override
    public PayOrderRes createOrder(ShopCartReq shopCartReq) throws Exception {
        // 1.查询当前用户是否存在未支付订单或掉单订单
        PayOrder payOrderReq = new PayOrder();
        payOrderReq.setUserId(shopCartReq.getUserId());
        payOrderReq.setProductId(shopCartReq.getProductId());
        
        PayOrder unpaidOrder = payOrderMapper.queryUnPayOrder(payOrderReq);
        
        if (null != unpaidOrder && Constants.OrderStatusEnum.PAY_WAIT.getCode().equals(unpaidOrder.getStatus())) {
            log.info("创建订单-存在，已存在未支付订单。userId:{} productId:{} orderId:{}", shopCartReq.getUserId(),
                    shopCartReq.getProductId(), unpaidOrder.getOrderId());
            return PayOrderRes.builder()
                    .orderId(unpaidOrder.getOrderId())
                    .payUrl(unpaidOrder.getPayUrl())
                    .build();
        } else if (null != unpaidOrder && Constants.OrderStatusEnum.CREATE.getCode().equals(unpaidOrder.getStatus())) {
            log.info("创建订单-存在，存在未创建支付单订单，创建支付单开始 userId:{} productId:{} orderId:{}",
                    shopCartReq.getUserId(), shopCartReq.getProductId(), unpaidOrder.getOrderId());
            PayOrder payOrder = doPrepayOrder(unpaidOrder.getProductId(), unpaidOrder.getProductName(),
                    unpaidOrder.getOrderId(), unpaidOrder.getTotalAmount());
            return PayOrderRes.builder()
                    .orderId(payOrder.getOrderId())
                    .payUrl(payOrder.getPayUrl())
                    .build();
        }
        
        // 2. 查询商品 & 创建订单
        ProductVO productVO = productRPC.queryProductByProductId(shopCartReq.getProductId());
        // 生成16位的随机数字字符串
        String orderId = RandomStringUtils.randomNumeric(16);
        payOrderMapper.insert(PayOrder.builder()
                .userId(shopCartReq.getUserId())
                .productId(shopCartReq.getProductId())
                .productName(productVO.getProductName())
                .orderId(orderId)
                .totalAmount(productVO.getPrice())
                .orderTime(LocalDateTime.now())
                .status(Constants.OrderStatusEnum.CREATE.getCode())
                .build());
        
        // 3.创建支付单
        PayOrder payOrder = doPrepayOrder(
                productVO.getProductId(),
                productVO.getProductName(),
                orderId,
                productVO.getPrice()
        );
        
        return PayOrderRes.builder()
                .orderId(orderId)
                .payUrl(payOrder.getPayUrl())
                .build();
    }
    
    /**
     * 修改支付订单
     *
     * @param orderId
     */
    @Override
    public void changeOrderPaySuccess(String orderId) {
        PayOrder payOrderReq = new PayOrder();
        payOrderReq.setOrderId(orderId);
        payOrderReq.setStatus(Constants.OrderStatusEnum.PAY_SUCCESS.getCode());
        payOrderMapper.changeOrderPaySuccess(payOrderReq);
        
        eventBus.post(JSON.toJSONString(payOrderReq));
    }
    
    /**
     * 获取没有支付的订单
     *
     * @return
     */
    @Override
    public List<String> queryNoPayNotifyOrder() {
        return payOrderMapper.queryNoPayNotifyOrder();
    }
    
    /**
     * 获取超时的订单
     *
     * @return
     */
    @Override
    public List<String> queryTimeoutCloseOrderList() {
        return payOrderMapper.queryTimeoutCloseOrderList();
    }
    
    /**
     * 关单的处理
     *
     * @param orderId
     * @return
     */
    @Override
    public boolean changeOrderClose(String orderId) {
        return payOrderMapper.changeOrderClose(orderId);
    }
    
    /**
     * 创建支付订单的操作
     *
     * @param productId   产品id
     * @param productName 产品名称
     * @param orderId     订单编号
     * @param totalAmount 总计金额
     * @return PayOrder
     * @throws AlipayApiException
     */
    private PayOrder doPrepayOrder(String productId, String productName, String orderId,
                                   BigDecimal totalAmount) throws AlipayApiException {
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setNotifyUrl(notifyUrl);
        request.setReturnUrl(returnUrl);
        
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", orderId);
        bizContent.put("total_amount", totalAmount.toString());
        bizContent.put("subject", productName);
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
        request.setBizContent(bizContent.toString());
        
        String form = alipayClient.pageExecute(request).getBody();
        
        PayOrder payOrder = new PayOrder();
        payOrder.setOrderId(orderId);
        payOrder.setPayUrl(form);
        payOrder.setStatus(Constants.OrderStatusEnum.PAY_WAIT.getCode());
        
        payOrderMapper.updateOrderPayInfo(payOrder);
        
        return payOrder;
    }
}
